/*******************************************************************************
 * Copyright (c) 2009 Markus Knittig and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Markus Knittig - initial API and implementation
 *******************************************************************************/
package com.googlecode.mylyn.core;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.ITask.PriorityLevel;
import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.core.data.TaskDataCollector;
import org.eclipse.mylyn.tasks.core.data.TaskMapper;
import org.eclipse.mylyn.tasks.core.data.TaskRelation;
import org.eclipse.mylyn.tasks.core.sync.ISynchronizationSession;

import com.google.gdata.client.projecthosting.IssuesQuery;
import com.google.gdata.data.projecthosting.IssuesEntry;
import com.google.gdata.data.projecthosting.IssuesFeed;
import com.googlecode.mylyn.core.client.GoogleCodeClientManager;
import com.googlecode.mylyn.core.client.IGoogleCodeClient;
import com.googlecode.mylyn.core.client.IGoogleCodeClientManager;
import com.googlecode.mylyn.core.util.GoogleCodeUtils;
import com.googlecode.mylyn.core.util.QueryUtils;
import com.googlecode.mylyn.core.util.RepositoryUtils;

/**
 * This class encapsulates common operations that can be performed on an
 * Google Code task repository.
 */
public class GoogleCodeRepositoryConnector extends AbstractRepositoryConnector {

    private final GoogleCodeTaskDataHandler taskDataHandler;

    private final IGoogleCodeClientManager clientManager;

    public GoogleCodeRepositoryConnector() {
        this.taskDataHandler = new GoogleCodeTaskDataHandler(this);
        this.clientManager = new GoogleCodeClientManager();
        if (GoogleCodeCorePlugin.getDefault() != null) {
            GoogleCodeCorePlugin.getDefault().setConnector(this);
        }
    }

    @Override
    public AbstractTaskDataHandler getTaskDataHandler() {
        return this.taskDataHandler;
    }

    public IGoogleCodeClientManager getClientManager() {
        return clientManager;
    }

    public IGoogleCodeClient getClient(TaskRepository repository) throws CoreException {
        return this.clientManager.getClient(repository);
    }

    @Override
    public boolean canCreateNewTask(TaskRepository repository) {
        return RepositoryUtils.isLoggedIn(repository);
    }

    @Override
    public boolean canCreateTaskFromKey(TaskRepository repository) {
        return true;
    }

    @Override
    public String getConnectorKind() {
        return GoogleCodeCorePlugin.CONNECTOR_KIND;
    }

    @Override
    public String getLabel() {
        return "Google Code";
    }

    @Override
    public String getRepositoryUrlFromTaskUrl(String taskFullUrl) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public TaskData getTaskData(TaskRepository taskRepository, String taskId,
            IProgressMonitor monitor) throws CoreException {
        IssuesEntry issue = this.getClient(taskRepository).getEntry(taskId, monitor);
        return this.taskDataHandler.updateTaskData(taskRepository, issue, monitor);
    }

    @Override
    public String getTaskIdFromTaskUrl(String taskFullUrl) {
        return null;
    }

    @Override
    public String getTaskUrl(String repositoryUrl, String taskId) {
        return "http://code.google.com/"
               + GoogleCodeUtils.extractProjectAffiliation(repositoryUrl)
               + "p/"
               + GoogleCodeUtils.extractProjectId(repositoryUrl)
               + "/issues/detail?id=" + taskId;
    }

    @Override
    public boolean hasTaskChanged(TaskRepository taskRepository, ITask task, TaskData taskData) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public IStatus performQuery(TaskRepository repository, IRepositoryQuery mylynQuery,
            TaskDataCollector collector, ISynchronizationSession session, IProgressMonitor monitor) {

        try {
            IGoogleCodeClient client = getClient(repository);
            IssuesFeed issues;
            if (mylynQuery.getAttributes().isEmpty()) {
                issues = client.getAllIssues(monitor);
            } else {
                IssuesQuery googleQuery = client.createNewIssuesQuery();
                QueryUtils.copyAttributes(mylynQuery, googleQuery);
                googleQuery.setMaxResults(Integer.MAX_VALUE);
                issues = client.getQueryIssues(googleQuery, monitor);
            }
            for (IssuesEntry issue : issues.getEntries()) {
                TaskData data = this.taskDataHandler.updateTaskData(repository, issue, monitor);
                collector.accept(data);
            }
            return Status.OK_STATUS;
        } catch (CoreException e) {
            return new Status(IStatus.ERROR, GoogleCodeCorePlugin.PLUGIN_ID, "could not execute query", e);
        }
    }

    @Override
    public void updateRepositoryConfiguration(TaskRepository taskRepository,
            IProgressMonitor monitor) throws CoreException {
        // TODO Auto-generated method stub

    }

    @Override
    public void updateTaskFromTaskData(TaskRepository repository, ITask task,
            TaskData taskData) {
        // copy and pasted from other connectors
        TaskMapper mapper;
        try {
            mapper = new GoogleCodeTaskMapper(taskData, clientManager.getClient(repository));
            mapper.applyTo(task);
        } catch (CoreException e) {
            StatusHandler.log(e.getStatus());
        }
    }

    @Override
    public Collection<TaskRelation> getTaskRelations(TaskData taskData) {
        List<TaskRelation> relations = new ArrayList<TaskRelation>();
        TaskAttribute attribute = taskData.getRoot().getAttribute(GoogleCodeAttribute.BLOCKED_ON.getKey());
        if (attribute != null && attribute.getValues().size() > 0) {
            for (String taskId : attribute.getValues()) {
                relations.add(TaskRelation.subtask(taskId.trim()));
            }
        }
        return relations;
    }

    static class GoogleCodeTaskMapper extends TaskMapper {

        public GoogleCodeTaskMapper(TaskData taskData, IGoogleCodeClient client) {
            super(taskData);
        }

        @Override
        public PriorityLevel getPriorityLevel() {
            String value = getPriority();
            if (value != null) {
                return LabelUtils.convertToMylyn(value);
            } else {
                return null;
            }
        }

    }

}
